import 'dart:async';
import 'dart:convert';
import 'dart:io';

import 'package:simple_server/src/context.dart';
import 'package:simple_server/src/log.dart';
import 'package:simple_server/src/middleware/middleware.dart';

class SimpleServer<T extends Context> {
  final List<Middleware<T>> _orderedMiddlewares = [];
  final Map<Type, Middleware<T>> _middlewareMap = {};

  void use<M extends Middleware<T>>(M middleware) {
    middleware.server = this;
    _orderedMiddlewares.add(middleware);
    _middlewareMap[M] = middleware;
  }

  M? getMiddleware<M extends Middleware<T>>() {
    return _middlewareMap[M] as M?;
  }

  Future<void> runMiddleware(T context, [int index = 0]) async {
    if (index >= _orderedMiddlewares.length) return;
    next() => runMiddleware(context, index + 1);
    await _orderedMiddlewares[index](context, next);
  }

  Future<void> handleRequest(T context) async {
    final response = context.response;
    try {
      await runMiddleware(context, 0);
    } catch (e, s) {
      error(e, s, 'handleRequest');
      response.statusCode = HttpStatus.internalServerError;
    } finally {
      await response.close();
    }
  }

  Future<void> waitExit(FutureOr<void> Function() stopServer) async {
    final exitCompleter = Completer<void>();
    final stop = exitCompleter.complete;
    final sigintListen = ProcessSignal.sigint.watch().listen(stop);
    final sigterm = Platform.isWindows ? null : ProcessSignal.sigterm;
    final sigtermListen = sigterm?.watch().listen(stop);
    final stdinListen = utf8.decoder.bind(stdin).listen((e) {
      e = e.trim();
      if (e == 'exit') stop();
    });
    await exitCompleter.future;
    await stdinListen.cancel();
    await sigintListen.cancel();
    await sigtermListen?.cancel();
    await stopServer();
  }
}